home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / a_utils / perl / msds-prl / prl386ld.zoo / doio.c < prev    next >
C/C++ Source or Header  |  1992-07-02  |  64KB  |  2,959 lines

  1. /* $RCSfile: doio.c,v $$Revision: 4.0.1.6 $$Date: 92/06/11 21:08:16 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    doio.c,v $
  9.  * Revision 4.0.1.6  92/06/11  21:08:16  lwall
  10.  * patch34: some systems don't declare h_errno extern in header files
  11.  * 
  12.  * Revision 4.0.1.5  92/06/08  13:00:21  lwall
  13.  * patch20: some machines don't define ENOTSOCK in errno.h
  14.  * patch20: new warnings for failed use of stat operators on filenames with \n
  15.  * patch20: wait failed when STDOUT or STDERR reopened to a pipe
  16.  * patch20: end of file latch not reset on reopen of STDIN
  17.  * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
  18.  * patch20: fixed memory leak on system() for vfork() machines
  19.  * patch20: get*by* routines now return something useful in a scalar context
  20.  * patch20: h_errno now accessible via $?
  21.  * 
  22.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  23.  * patch11: prepared for ctype implementations that don't define isascii()
  24.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  25.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  26.  * patch11: certain perl errors should set EBADF so that $! looks better
  27.  * patch11: truncate on a closed filehandle could dump
  28.  * patch11: stats of _ forgot whether prior stat was actually lstat
  29.  * patch11: -T returned true on NFS directory
  30.  * 
  31.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  32.  * patch10: read didn't work from character special files open for writing
  33.  * patch10: close-on-exec wrongly set on system file descriptors
  34.  * 
  35.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  36.  * patch4: new copyright notice
  37.  * patch4: system fd's are now treated specially
  38.  * patch4: added $^F variable to specify maximum system fd, default 2
  39.  * patch4: character special files now opened with bidirectional stdio buffers
  40.  * patch4: taintchecks could improperly modify parent in vfork()
  41.  * patch4: many, many itty-bitty portability fixes
  42.  * 
  43.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  44.  * patch1: hopefully straightened out some of the Xenix mess
  45.  * 
  46.  * Revision 4.0  91/03/20  01:07:06  lwall
  47.  * 4.0 baseline.
  48.  * 
  49.  */
  50.  
  51. #include "EXTERN.h"
  52. #include "perl.h"
  53.  
  54. #ifdef HAS_SOCKET
  55. #include <sys/socket.h>
  56. #include <netdb.h>
  57. #ifndef ENOTSOCK
  58. #include <net/errno.h>
  59. #endif
  60. #endif
  61.  
  62. #ifdef HAS_SELECT
  63. #ifdef I_SYS_SELECT
  64. #ifndef I_SYS_TIME
  65. #include <sys/select.h>
  66. #endif
  67. #endif
  68. #endif
  69.  
  70. #ifdef HOST_NOT_FOUND
  71. extern int h_errno;
  72. #endif
  73.  
  74. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  75. #include <sys/ipc.h>
  76. #ifdef HAS_MSG
  77. #include <sys/msg.h>
  78. #endif
  79. #ifdef HAS_SEM
  80. #include <sys/sem.h>
  81. #endif
  82. #ifdef HAS_SHM
  83. #include <sys/shm.h>
  84. #endif
  85. #endif
  86.  
  87. #ifdef I_PWD
  88. #include <pwd.h>
  89. #endif
  90. #ifdef I_GRP
  91. #include <grp.h>
  92. #endif
  93. #ifdef I_UTIME
  94. #include <utime.h>
  95. #endif
  96. #ifdef I_FCNTL
  97. #include <fcntl.h>
  98. #endif
  99. #ifdef I_SYS_FILE
  100. #include <sys/file.h>
  101. #endif
  102.  
  103. int laststatval = -1;
  104. int laststype = O_STAT;
  105.  
  106. static char* warn_nl = "Unsuccessful %s on filename containing newline";
  107.  
  108. bool
  109. do_open(stab,name,len)
  110. STAB *stab;
  111. register char *name;
  112. int len;
  113. {
  114.     FILE *fp;
  115.     register STIO *stio = stab_io(stab);
  116.     char *myname = savestr(name);
  117.     int result;
  118.     int fd;
  119.     int writing = 0;
  120.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  121.     FILE *saveifp = Nullfp;
  122.     FILE *saveofp = Nullfp;
  123.     char savetype = ' ';
  124.  
  125.     mode[0] = mode[1] = mode[2] = '\0';
  126.     name = myname;
  127.     forkprocess = 1;        /* assume true if no fork */
  128.     while (len && isSPACE(name[len-1]))
  129.     name[--len] = '\0';
  130.     if (!stio)
  131.     stio = stab_io(stab) = stio_new();
  132.     else if (stio->ifp) {
  133.     fd = fileno(stio->ifp);
  134.     if (stio->type == '-')
  135.         result = 0;
  136.     else if (fd <= maxsysfd) {
  137.         saveifp = stio->ifp;
  138.         saveofp = stio->ofp;
  139.         savetype = stio->type;
  140.         result = 0;
  141.     }
  142.     else if (stio->type == '|')
  143.         result = mypclose(stio->ifp);
  144.     else if (stio->ifp != stio->ofp) {
  145.         if (stio->ofp) {
  146.         result = fclose(stio->ofp);
  147.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  148.         }
  149.         else
  150.         result = fclose(stio->ifp);
  151.     }
  152.     else
  153.         result = fclose(stio->ifp);
  154.     if (result == EOF && fd > maxsysfd)
  155.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  156.           stab_ename(stab));
  157.     stio->ofp = stio->ifp = Nullfp;
  158.     }
  159.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  160.     mode[1] = *name++;
  161.     mode[2] = '\0';
  162.     --len;
  163.     writing = 1;
  164.     }
  165.     else  {
  166.     mode[1] = '\0';
  167.     }
  168.     stio->type = *name;
  169.     if (*name == '|') {
  170.     /*SUPPRESS 530*/
  171.     for (name++; isSPACE(*name); name++) ;
  172. #ifdef TAINT
  173.     taintenv();
  174.     taintproper("Insecure dependency in piped open");
  175. #endif
  176.     fp = mypopen(name,"w");
  177.     writing = 1;
  178.     }
  179.     else if (*name == '>') {
  180. #ifdef TAINT
  181.     taintproper("Insecure dependency in open");
  182. #endif
  183.     name++;
  184.     if (*name == '>') {
  185.         mode[0] = stio->type = 'a';
  186.         name++;
  187.     }
  188.     else
  189.         mode[0] = 'w';
  190.     writing = 1;
  191.     if (*name == '&') {
  192.       duplicity:
  193.         name++;
  194.         while (isSPACE(*name))
  195.         name++;
  196.         if (isDIGIT(*name))
  197.         fd = atoi(name);
  198.         else {
  199.         stab = stabent(name,FALSE);
  200.         if (!stab || !stab_io(stab)) {
  201. #ifdef EINVAL
  202.             errno = EINVAL;
  203. #endif
  204.             goto say_false;
  205.         }
  206.         if (stab_io(stab) && stab_io(stab)->ifp) {
  207.             fd = fileno(stab_io(stab)->ifp);
  208.             if (stab_io(stab)->type == 's')
  209.             stio->type = 's';
  210.         }
  211.         else
  212.             fd = -1;
  213.         }
  214.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  215.         close(fd);
  216.         }
  217.     }
  218.     else {
  219.         while (isSPACE(*name))
  220.         name++;
  221.         if (strEQ(name,"-")) {
  222.         fp = stdout;
  223.         stio->type = '-';
  224.         }
  225.         else  {
  226.         fp = fopen(name,mode);
  227.         }
  228.     }
  229.     }
  230.     else {
  231.     if (*name == '<') {
  232.         mode[0] = 'r';
  233.         name++;
  234.         while (isSPACE(*name))
  235.         name++;
  236.         if (*name == '&')
  237.         goto duplicity;
  238.         if (strEQ(name,"-")) {
  239.         fp = stdin;
  240.         stio->type = '-';
  241.         }
  242.         else
  243.         fp = fopen(name,mode);
  244.     }
  245.     else if (name[len-1] == '|') {
  246. #ifdef TAINT
  247.         taintenv();
  248.         taintproper("Insecure dependency in piped open");
  249. #endif
  250.         name[--len] = '\0';
  251.         while (len && isSPACE(name[len-1]))
  252.         name[--len] = '\0';
  253.         /*SUPPRESS 530*/
  254.         for (; isSPACE(*name); name++) ;
  255.         fp = mypopen(name,"r");
  256.         stio->type = '|';
  257.     }
  258.     else {
  259.         stio->type = '<';
  260.         /*SUPPRESS 530*/
  261.         for (; isSPACE(*name); name++) ;
  262.         if (strEQ(name,"-")) {
  263.         fp = stdin;
  264.         stio->type = '-';
  265.         }
  266.         else
  267.         fp = fopen(name,"r");
  268.     }
  269.     }
  270.     if (!fp) {
  271.     if (dowarn && stio->type == '<' && index(name, '\n'))
  272.         warn(warn_nl, "open");
  273.     Safefree(myname);
  274.     goto say_false;
  275.     }
  276.     Safefree(myname);
  277.     if (stio->type &&
  278.       stio->type != '|' && stio->type != '-') {
  279.     if (fstat(fileno(fp),&statbuf) < 0) {
  280.         (void)fclose(fp);
  281.         goto say_false;
  282.     }
  283.     if (S_ISSOCK(statbuf.st_mode))
  284.         stio->type = 's';    /* in case a socket was passed in to us */
  285. #ifdef HAS_SOCKET
  286.     else if (
  287. #ifdef S_IFMT
  288.         !(statbuf.st_mode & S_IFMT)
  289. #else
  290.         !statbuf.st_mode
  291. #endif
  292.     ) {
  293.         int buflen = sizeof tokenbuf;
  294.         if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
  295.         || errno != ENOTSOCK)
  296.         stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
  297.                 /* but some return 0 for streams too, sigh */
  298.     }
  299. #endif
  300.     }
  301.     if (saveifp) {        /* must use old fp? */
  302.     fd = fileno(saveifp);
  303.     if (saveofp) {
  304.         fflush(saveofp);        /* emulate fclose() */
  305.         if (saveofp != saveifp) {    /* was a socket? */
  306.         fclose(saveofp);
  307.         if (fd > 2)
  308.             Safefree(saveofp);
  309.         }
  310.     }
  311.     if (fd != fileno(fp)) {
  312.         int pid;
  313.         STR *str;
  314.  
  315.         dup2(fileno(fp), fd);
  316.         str = afetch(fdpid,fileno(fp),TRUE);
  317.         pid = str->str_u.str_useful;
  318.         str->str_u.str_useful = 0;
  319.         str = afetch(fdpid,fd,TRUE);
  320.         str->str_u.str_useful = pid;
  321.         fclose(fp);
  322.  
  323.     }
  324.     fp = saveifp;
  325.     clearerr(fp);
  326.     }
  327. #if defined(HAS_FCNTL) && defined(F_SETFD)
  328.     fd = fileno(fp);
  329.     fcntl(fd,F_SETFD,fd > maxsysfd);
  330. #endif
  331.     stio->ifp = fp;
  332.     if (writing) {
  333.     if (stio->type == 's'
  334.       || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  335.         if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
  336.         fclose(fp);
  337.         stio->ifp = Nullfp;
  338.         goto say_false;
  339.         }
  340.     }
  341.     else
  342.         stio->ofp = fp;
  343.     }
  344.     return TRUE;
  345.  
  346. say_false:
  347.     stio->ifp = saveifp;
  348.     stio->ofp = saveofp;
  349.     stio->type = savetype;
  350.     return FALSE;
  351. }
  352.  
  353. FILE *
  354. nextargv(stab)
  355. register STAB *stab;
  356. {
  357.     register STR *str;
  358. #ifndef FLEXFILENAMES
  359.     int filedev;
  360.     int fileino;
  361. #endif
  362.     int fileuid;
  363.     int filegid;
  364.     static int filemode = 0;
  365.     static int lastfd;
  366.     static char *oldname;
  367.  
  368.     if (!argvoutstab)
  369.     argvoutstab = stabent("ARGVOUT",TRUE);
  370.     if (filemode & (S_ISUID|S_ISGID)) {
  371.     fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
  372. #ifdef HAS_FCHMOD
  373.     (void)fchmod(lastfd,filemode);
  374. #else
  375.     (void)chmod(oldname,filemode);
  376. #endif
  377.     }
  378.     filemode = 0;
  379.     while (alen(stab_xarray(stab)) >= 0) {
  380.     str = ashift(stab_xarray(stab));
  381.     str_sset(stab_val(stab),str);
  382.     STABSET(stab_val(stab));
  383.     oldname = str_get(stab_val(stab));
  384.     if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
  385.         if (inplace) {
  386. #ifdef TAINT
  387.         taintproper("Insecure dependency in inplace open");
  388. #endif
  389.         if (strEQ(oldname,"-")) {
  390.             str_free(str);
  391.             defoutstab = stabent("STDOUT",TRUE);
  392.             return stab_io(stab)->ifp;
  393.         }
  394. #ifndef FLEXFILENAMES
  395.         filedev = statbuf.st_dev;
  396.         fileino = statbuf.st_ino;
  397. #endif
  398.         filemode = statbuf.st_mode;
  399.         fileuid = statbuf.st_uid;
  400.         filegid = statbuf.st_gid;
  401.         if (!S_ISREG(filemode)) {
  402.             warn("Can't do inplace edit: %s is not a regular file",
  403.               oldname );
  404.             do_close(stab,FALSE);
  405.             str_free(str);
  406.             continue;
  407.         }
  408.         if (*inplace) {
  409. #ifdef SUFFIX
  410.             add_suffix(str,inplace);
  411. #else
  412.             str_cat(str,inplace);
  413. #endif
  414. #ifndef FLEXFILENAMES
  415.             if (stat(str->str_ptr,&statbuf) >= 0
  416.               && statbuf.st_dev == filedev
  417.               && statbuf.st_ino == fileino ) {
  418.             warn("Can't do inplace edit: %s > 14 characters",
  419.               str->str_ptr );
  420.             do_close(stab,FALSE);
  421.             str_free(str);
  422.             continue;
  423.             }
  424. #endif
  425. #ifdef HAS_RENAME
  426. #ifndef DOSISH
  427.             if (rename(oldname,str->str_ptr) < 0) {
  428.             warn("Can't rename %s to %s: %s, skipping file",
  429.               oldname, str->str_ptr, strerror(errno) );
  430.             do_close(stab,FALSE);
  431.             str_free(str);
  432.             continue;
  433.             }
  434. #else
  435.             do_close(stab,FALSE);
  436.             (void)unlink(str->str_ptr);
  437.             (void)rename(oldname,str->str_ptr);
  438.             do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
  439. #endif /* MSDOS */
  440. #else
  441.             (void)UNLINK(str->str_ptr);
  442.             if (link(oldname,str->str_ptr) < 0) {
  443.             warn("Can't rename %s to %s: %s, skipping file",
  444.               oldname, str->str_ptr, strerror(errno) );
  445.             do_close(stab,FALSE);
  446.             str_free(str);
  447.             continue;
  448.             }
  449.             (void)UNLINK(oldname);
  450. #endif
  451.         }
  452.         else {
  453. #ifndef DOSISH
  454.             if (UNLINK(oldname) < 0) {
  455.             warn("Can't rename %s to %s: %s, skipping file",
  456.               oldname, str->str_ptr, strerror(errno) );
  457.             do_close(stab,FALSE);
  458.             str_free(str);
  459.             continue;
  460.             }
  461. #else
  462.             fatal("Can't do inplace edit without backup");
  463. #endif
  464.         }
  465.  
  466.         str_nset(str,">",1);
  467.         str_cat(str,oldname);
  468.         errno = 0;        /* in case sprintf set errno */
  469.         if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
  470.             warn("Can't do inplace edit on %s: %s",
  471.               oldname, strerror(errno) );
  472.             do_close(stab,FALSE);
  473.             str_free(str);
  474.             continue;
  475.         }
  476.         defoutstab = argvoutstab;
  477.         lastfd = fileno(stab_io(argvoutstab)->ifp);
  478.         (void)fstat(lastfd,&statbuf);
  479. #ifdef HAS_FCHMOD
  480.         (void)fchmod(lastfd,filemode);
  481. #else
  482.         (void)chmod(oldname,filemode);
  483. #endif
  484.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  485. #ifdef HAS_FCHOWN
  486.             (void)fchown(lastfd,fileuid,filegid);
  487. #else
  488. #ifdef HAS_CHOWN
  489.             (void)chown(oldname,fileuid,filegid);
  490. #endif
  491. #endif
  492.         }
  493.         }
  494.         str_free(str);
  495.         return stab_io(stab)->ifp;
  496.     }
  497.     else
  498.         fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
  499.     str_free(str);
  500.     }
  501.     if (inplace) {
  502.     (void)do_close(argvoutstab,FALSE);
  503.     defoutstab = stabent("STDOUT",TRUE);
  504.     }
  505.     return Nullfp;
  506. }
  507.  
  508. #ifdef HAS_PIPE
  509. void
  510. do_pipe(str, rstab, wstab)
  511. STR *str;
  512. STAB *rstab;
  513. STAB *wstab;
  514. {
  515.     register STIO *rstio;
  516.     register STIO *wstio;
  517.     int fd[2];
  518.  
  519.     if (!rstab)
  520.     goto badexit;
  521.     if (!wstab)
  522.     goto badexit;
  523.  
  524.     rstio = stab_io(rstab);
  525.     wstio = stab_io(wstab);
  526.  
  527.     if (!rstio)
  528.     rstio = stab_io(rstab) = stio_new();
  529.     else if (rstio->ifp)
  530.     do_close(rstab,FALSE);
  531.     if (!wstio)
  532.     wstio = stab_io(wstab) = stio_new();
  533.     else if (wstio->ifp)
  534.     do_close(wstab,FALSE);
  535.  
  536.     if (pipe(fd) < 0)
  537.     goto badexit;
  538.     rstio->ifp = fdopen(fd[0], "r");
  539.     wstio->ofp = fdopen(fd[1], "w");
  540.     wstio->ifp = wstio->ofp;
  541.     rstio->type = '<';
  542.     wstio->type = '>';
  543.     if (!rstio->ifp || !wstio->ofp) {
  544.     if (rstio->ifp) fclose(rstio->ifp);
  545.     else close(fd[0]);
  546.     if (wstio->ofp) fclose(wstio->ofp);
  547.     else close(fd[1]);
  548.     goto badexit;
  549.     }
  550.  
  551.     str_sset(str,&str_yes);
  552.     return;
  553.  
  554. badexit:
  555.     str_sset(str,&str_undef);
  556.     return;
  557. }
  558. #endif
  559.  
  560. bool
  561. do_close(stab,explicit)
  562. STAB *stab;
  563. bool explicit;
  564. {
  565.     bool retval = FALSE;
  566.     register STIO *stio;
  567.     int status;
  568.  
  569.     if (!stab)
  570.     stab = argvstab;
  571.     if (!stab) {
  572.     errno = EBADF;
  573.     return FALSE;
  574.     }
  575.     stio = stab_io(stab);
  576.     if (!stio) {        /* never opened */
  577.     if (dowarn && explicit)
  578.         warn("Close on unopened file <%s>",stab_ename(stab));
  579.     return FALSE;
  580.     }
  581.     if (stio->ifp) {
  582.     if (stio->type == '|') {
  583.         status = mypclose(stio->ifp);
  584.         retval = (status == 0);
  585.         statusvalue = (unsigned short)status & 0xffff;
  586.     }
  587.     else if (stio->type == '-')
  588.         retval = TRUE;
  589.     else {
  590.         if (stio->ofp && stio->ofp != stio->ifp) {        /* a socket */
  591.         retval = (fclose(stio->ofp) != EOF);
  592.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  593.         }
  594.         else
  595.         retval = (fclose(stio->ifp) != EOF);
  596.     }
  597.     stio->ofp = stio->ifp = Nullfp;
  598.     }
  599.     if (explicit)
  600.     stio->lines = 0;
  601.     stio->type = ' ';
  602.     return retval;
  603. }
  604.  
  605. bool
  606. do_eof(stab)
  607. STAB *stab;
  608. {
  609.     register STIO *stio;
  610.     int ch;
  611.  
  612.     if (!stab) {            /* eof() */
  613.     if (argvstab)
  614.         stio = stab_io(argvstab);
  615.     else
  616.         return TRUE;
  617.     }
  618.     else
  619.     stio = stab_io(stab);
  620.  
  621.     if (!stio)
  622.     return TRUE;
  623.  
  624.     while (stio->ifp) {
  625.  
  626. #ifdef STDSTDIO            /* (the code works without this) */
  627.     if (stio->ifp->_cnt > 0)    /* cheat a little, since */
  628.         return FALSE;        /* this is the most usual case */
  629. #endif
  630.  
  631.     ch = getc(stio->ifp);
  632.     if (ch != EOF) {
  633.         (void)ungetc(ch, stio->ifp);
  634.         return FALSE;
  635.     }
  636. #ifdef STDSTDIO
  637.     if (stio->ifp->_cnt < -1)
  638.         stio->ifp->_cnt = -1;
  639. #endif
  640.     if (!stab) {            /* not necessarily a real EOF yet? */
  641.         if (!nextargv(argvstab))    /* get another fp handy */
  642.         return TRUE;
  643.     }
  644.     else
  645.         return TRUE;        /* normal fp, definitely end of file */
  646.     }
  647.     return TRUE;
  648. }
  649.  
  650. long
  651. do_tell(stab)
  652. STAB *stab;
  653. {
  654.     register STIO *stio;
  655.  
  656.     if (!stab)
  657.     goto phooey;
  658.  
  659.     stio = stab_io(stab);
  660.     if (!stio || !stio->ifp)
  661.     goto phooey;
  662.  
  663. #ifdef ULTRIX_STDIO_BOTCH
  664.     if (feof(stio->ifp))
  665.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  666. #endif
  667.  
  668.     return ftell(stio->ifp);
  669.  
  670. phooey:
  671.     if (dowarn)
  672.     warn("tell() on unopened file");
  673.     errno = EBADF;
  674.     return -1L;
  675. }
  676.  
  677. bool
  678. do_seek(stab, pos, whence)
  679. STAB *stab;
  680. long pos;
  681. int whence;
  682. {
  683.     register STIO *stio;
  684.  
  685.     if (!stab)
  686.     goto nuts;
  687.  
  688.     stio = stab_io(stab);
  689.     if (!stio || !stio->ifp)
  690.     goto nuts;
  691.  
  692. #ifdef ULTRIX_STDIO_BOTCH
  693.     if (feof(stio->ifp))
  694.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  695. #endif
  696.  
  697.     return fseek(stio->ifp, pos, whence) >= 0;
  698.  
  699. nuts:
  700.     if (dowarn)
  701.     warn("seek() on unopened file");
  702.     errno = EBADF;
  703.     return FALSE;
  704. }
  705.  
  706. int
  707. do_ctl(optype,stab,func,argstr)
  708. int optype;
  709. STAB *stab;
  710. int func;
  711. STR *argstr;
  712. {
  713.     register STIO *stio;
  714.     register char *s;
  715.     int retval;
  716.  
  717.     if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
  718.     errno = EBADF;    /* well, sort of... */
  719.     return -1;
  720.     }
  721.  
  722.     if (argstr->str_pok || !argstr->str_nok) {
  723.     if (!argstr->str_pok)
  724.         s = str_get(argstr);
  725.  
  726. #ifdef IOCPARM_MASK
  727. #ifndef IOCPARM_LEN
  728. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  729. #endif
  730. #endif
  731. #ifdef IOCPARM_LEN
  732.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  733. #else
  734.     retval = 256;            /* otherwise guess at what's safe */
  735. #endif
  736.     if (argstr->str_cur < retval) {
  737.         Str_Grow(argstr,retval+1);
  738.         argstr->str_cur = retval;
  739.     }
  740.  
  741.     s = argstr->str_ptr;
  742.     s[argstr->str_cur] = 17;    /* a little sanity check here */
  743.     }
  744.     else {
  745.     retval = (int)str_gnum(argstr);
  746. #ifdef DOSISH
  747.     s = (char*)(long)retval;        /* ouch */
  748. #else
  749.     s = (char*)retval;        /* ouch */
  750. #endif
  751.     }
  752.  
  753. #ifndef lint
  754.     if (optype == O_IOCTL)
  755.     retval = ioctl(fileno(stio->ifp), func, s);
  756.     else
  757. #ifdef DOSISH
  758.     fatal("fcntl is not implemented");
  759. #else
  760. #ifdef HAS_FCNTL
  761.     retval = fcntl(fileno(stio->ifp), func, s);
  762. #else
  763.     fatal("fcntl is not implemented");
  764. #endif
  765. #endif
  766. #else /* lint */
  767.     retval = 0;
  768. #endif /* lint */
  769.  
  770.     if (argstr->str_pok) {
  771.     if (s[argstr->str_cur] != 17)
  772.         fatal("Return value overflowed string");
  773.     s[argstr->str_cur] = 0;        /* put our null back */
  774.     }
  775.     return retval;
  776. }
  777.  
  778. int
  779. do_stat(str,arg,gimme,arglast)
  780. STR *str;
  781. register ARG *arg;
  782. int gimme;
  783. int *arglast;
  784. {
  785.     register ARRAY *ary = stack;
  786.     register int sp = arglast[0] + 1;
  787.     int max = 13;
  788.  
  789.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  790.     tmpstab = arg[1].arg_ptr.arg_stab;
  791.     if (tmpstab != defstab) {
  792.         laststype = O_STAT;
  793.         statstab = tmpstab;
  794.         str_set(statname,"");
  795.         if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  796.           fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
  797.         max = 0;
  798.         laststatval = -1;
  799.         }
  800.     }
  801.     else if (laststatval < 0)
  802.         max = 0;
  803.     }
  804.     else {
  805.     str_set(statname,str_get(ary->ary_array[sp]));
  806.     statstab = Nullstab;
  807. #ifdef HAS_LSTAT
  808.     laststype = arg->arg_type;
  809.     if (arg->arg_type == O_LSTAT)
  810.         laststatval = lstat(str_get(statname),&statcache);
  811.     else
  812. #endif
  813.         laststatval = stat(str_get(statname),&statcache);
  814.     if (laststatval < 0) {
  815.         if (dowarn && index(str_get(statname), '\n'))
  816.         warn(warn_nl, "stat");
  817.         max = 0;
  818.     }
  819.     }
  820.  
  821.     if (gimme != G_ARRAY) {
  822.     if (max)
  823.         str_sset(str,&str_yes);
  824.     else
  825.         str_sset(str,&str_undef);
  826.     STABSET(str);
  827.     ary->ary_array[sp] = str;
  828.     return sp;
  829.     }
  830.     sp--;
  831.     if (max) {
  832. #ifndef lint
  833.     (void)astore(ary,++sp,
  834.       str_2mortal(str_nmake((double)statcache.st_dev)));
  835.     (void)astore(ary,++sp,
  836.       str_2mortal(str_nmake((double)statcache.st_ino)));
  837.     (void)astore(ary,++sp,
  838.       str_2mortal(str_nmake((double)statcache.st_mode)));
  839.     (void)astore(ary,++sp,
  840.       str_2mortal(str_nmake((double)statcache.st_nlink)));
  841.     (void)astore(ary,++sp,
  842.       str_2mortal(str_nmake((double)statcache.st_uid)));
  843.     (void)astore(ary,++sp,
  844.       str_2mortal(str_nmake((double)statcache.st_gid)));
  845.     (void)astore(ary,++sp,
  846.       str_2mortal(str_nmake((double)statcache.st_rdev)));
  847.     (void)astore(ary,++sp,
  848.       str_2mortal(str_nmake((double)statcache.st_size)));
  849.     (void)astore(ary,++sp,
  850.       str_2mortal(str_nmake((double)statcache.st_atime)));
  851.     (void)astore(ary,++sp,
  852.       str_2mortal(str_nmake((double)statcache.st_mtime)));
  853.     (void)astore(ary,++sp,
  854.       str_2mortal(str_nmake((double)statcache.st_ctime)));
  855. #ifdef STATBLOCKS
  856.     (void)astore(ary,++sp,
  857.       str_2mortal(str_nmake((double)statcache.st_blksize)));
  858.     (void)astore(ary,++sp,
  859.       str_2mortal(str_nmake((double)statcache.st_blocks)));
  860. #else
  861.     (void)astore(ary,++sp,
  862.       str_2mortal(str_make("",0)));
  863.     (void)astore(ary,++sp,
  864.       str_2mortal(str_make("",0)));
  865. #endif
  866. #else /* lint */
  867.     (void)astore(ary,++sp,str_nmake(0.0));
  868. #endif /* lint */
  869.     }
  870.     return sp;
  871. }
  872.  
  873. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
  874.     /* code courtesy of William Kucharski */
  875. #define HAS_CHSIZE
  876.  
  877. int chsize(fd, length)
  878. int fd;            /* file descriptor */
  879. off_t length;        /* length to set file to */
  880. {
  881.     extern long lseek();
  882.     struct flock fl;
  883.     struct stat filebuf;
  884.  
  885.     if (fstat(fd, &filebuf) < 0)
  886.     return -1;
  887.  
  888.     if (filebuf.st_size < length) {
  889.  
  890.     /* extend file length */
  891.  
  892.     if ((lseek(fd, (length - 1), 0)) < 0)
  893.         return -1;
  894.  
  895.     /* write a "0" byte */
  896.  
  897.     if ((write(fd, "", 1)) != 1)
  898.         return -1;
  899.     }
  900.     else {
  901.     /* truncate length */
  902.  
  903.     fl.l_whence = 0;
  904.     fl.l_len = 0;
  905.     fl.l_start = length;
  906.     fl.l_type = F_WRLCK;    /* write lock on file space */
  907.  
  908.     /*
  909.     * This relies on the UNDOCUMENTED F_FREESP argument to
  910.     * fcntl(2), which truncates the file so that it ends at the
  911.     * position indicated by fl.l_start.
  912.     *
  913.     * Will minor miracles never cease?
  914.     */
  915.  
  916.     if (fcntl(fd, F_FREESP, &fl) < 0)
  917.         return -1;
  918.  
  919.     }
  920.  
  921.     return 0;
  922. }
  923. #endif /* F_FREESP */
  924.  
  925. int                    /*SUPPRESS 590*/
  926. do_truncate(str,arg,gimme,arglast)
  927. STR *str;
  928. register ARG *arg;
  929. int gimme;
  930. int *arglast;
  931. {
  932.     register ARRAY *ary = stack;
  933.     register int sp = arglast[0] + 1;
  934.     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
  935.     int result = 1;
  936.     STAB *tmpstab;
  937.  
  938. #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
  939. #ifdef HAS_TRUNCATE
  940.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  941.     tmpstab = arg[1].arg_ptr.arg_stab;
  942.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  943.       ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
  944.         result = 0;
  945.     }
  946.     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
  947.     result = 0;
  948. #else
  949.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  950.     tmpstab = arg[1].arg_ptr.arg_stab;
  951.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  952.       chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
  953.         result = 0;
  954.     }
  955.     else {
  956.     int tmpfd;
  957.  
  958.     if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
  959.         result = 0;
  960.     else {
  961.         if (chsize(tmpfd, len) < 0)
  962.         result = 0;
  963.         close(tmpfd);
  964.     }
  965.     }
  966. #endif
  967.  
  968.     if (result)
  969.     str_sset(str,&str_yes);
  970.     else
  971.     str_sset(str,&str_undef);
  972.     STABSET(str);
  973.     ary->ary_array[sp] = str;
  974.     return sp;
  975. #else
  976.     fatal("truncate not implemented");
  977. #endif
  978. }
  979.  
  980. int
  981. looks_like_number(str)
  982. STR *str;
  983. {
  984.     register char *s;
  985.     register char *send;
  986.  
  987.     if (!str->str_pok)
  988.     return TRUE;
  989.     s = str->str_ptr; 
  990.     send = s + str->str_cur;
  991.     while (isSPACE(*s))
  992.     s++;
  993.     if (s >= send)
  994.     return FALSE;
  995.     if (*s == '+' || *s == '-')
  996.     s++;
  997.     while (isDIGIT(*s))
  998.     s++;
  999.     if (s == send)
  1000.     return TRUE;
  1001.     if (*s == '.') 
  1002.     s++;
  1003.     else if (s == str->str_ptr)
  1004.     return FALSE;
  1005.     while (isDIGIT(*s))
  1006.     s++;
  1007.     if (s == send)
  1008.     return TRUE;
  1009.     if (*s == 'e' || *s == 'E') {
  1010.     s++;
  1011.     if (*s == '+' || *s == '-')
  1012.         s++;
  1013.     while (isDIGIT(*s))
  1014.         s++;
  1015.     }
  1016.     while (isSPACE(*s))
  1017.     s++;
  1018.     if (s >= send)
  1019.     return TRUE;
  1020.     return FALSE;
  1021. }
  1022.  
  1023. bool
  1024. do_print(str,fp)
  1025. register STR *str;
  1026. FILE *fp;
  1027. {
  1028.     register char *tmps;
  1029.  
  1030.     if (!fp) {
  1031.     if (dowarn)
  1032.         warn("print to unopened file");
  1033.     errno = EBADF;
  1034.     return FALSE;
  1035.     }
  1036.     if (!str)
  1037.     return TRUE;
  1038.     if (ofmt &&
  1039.       ((str->str_nok && str->str_u.str_nval != 0.0)
  1040.        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
  1041.     fprintf(fp, ofmt, str->str_u.str_nval);
  1042.     return !ferror(fp);
  1043.     }
  1044.     else {
  1045.     tmps = str_get(str);
  1046.     if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
  1047.       && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
  1048.         STR *tmpstr = str_mortal(&str_undef);
  1049.         stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
  1050.         str = tmpstr;
  1051.         tmps = str->str_ptr;
  1052.         putc('*',fp);
  1053.     }
  1054.     if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
  1055.         return FALSE;
  1056.     }
  1057.     return TRUE;
  1058. }
  1059.  
  1060. bool
  1061. do_aprint(arg,fp,arglast)
  1062. register ARG *arg;
  1063. register FILE *fp;
  1064. int *arglast;
  1065. {
  1066.     register STR **st = stack->ary_array;
  1067.     register int sp = arglast[1];
  1068.     register int retval;
  1069.     register int items = arglast[2] - sp;
  1070.  
  1071.     if (!fp) {
  1072.     if (dowarn)
  1073.         warn("print to unopened file");
  1074.     errno = EBADF;
  1075.     return FALSE;
  1076.     }
  1077.     st += ++sp;
  1078.     if (arg->arg_type == O_PRTF) {
  1079.     do_sprintf(arg->arg_ptr.arg_str,items,st);
  1080.     retval = do_print(arg->arg_ptr.arg_str,fp);
  1081.     }
  1082.     else {
  1083.     retval = (items <= 0);
  1084.     for (; items > 0; items--,st++) {
  1085.         if (retval && ofslen) {
  1086.         if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
  1087.             retval = FALSE;
  1088.             break;
  1089.         }
  1090.         }
  1091.         if (!(retval = do_print(*st, fp)))
  1092.         break;
  1093.     }
  1094.     if (retval && orslen)
  1095.         if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
  1096.         retval = FALSE;
  1097.     }
  1098.     return retval;
  1099. }
  1100.  
  1101. int
  1102. mystat(arg,str)
  1103. ARG *arg;
  1104. STR *str;
  1105. {
  1106.     STIO *stio;
  1107.  
  1108.     if (arg[1].arg_type & A_DONT) {
  1109.     stio = stab_io(arg[1].arg_ptr.arg_stab);
  1110.     if (stio && stio->ifp) {
  1111.         statstab = arg[1].arg_ptr.arg_stab;
  1112.         str_set(statname,"");
  1113.         laststype = O_STAT;
  1114.         return (laststatval = fstat(fileno(stio->ifp), &statcache));
  1115.     }
  1116.     else {
  1117.         if (arg[1].arg_ptr.arg_stab == defstab)
  1118.         return laststatval;
  1119.         if (dowarn)
  1120.         warn("Stat on unopened file <%s>",
  1121.           stab_ename(arg[1].arg_ptr.arg_stab));
  1122.         statstab = Nullstab;
  1123.         str_set(statname,"");
  1124.         return (laststatval = -1);
  1125.     }
  1126.     }
  1127.     else {
  1128.     statstab = Nullstab;
  1129.     str_set(statname,str_get(str));
  1130.     laststype = O_STAT;
  1131.     laststatval = stat(str_get(str),&statcache);
  1132.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1133.         warn(warn_nl, "stat");
  1134.     return laststatval;
  1135.     }
  1136. }
  1137.  
  1138. int
  1139. mylstat(arg,str)
  1140. ARG *arg;
  1141. STR *str;
  1142. {
  1143.     if (arg[1].arg_type & A_DONT) {
  1144.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1145.         if (laststype != O_LSTAT)
  1146.         fatal("The stat preceding -l _ wasn't an lstat");
  1147.         return laststatval;
  1148.     }
  1149.     fatal("You can't use -l on a filehandle");
  1150.     }
  1151.  
  1152.     laststype = O_LSTAT;
  1153.     statstab = Nullstab;
  1154.     str_set(statname,str_get(str));
  1155. #ifdef HAS_LSTAT
  1156.     laststatval = lstat(str_get(str),&statcache);
  1157. #else
  1158.     laststatval = stat(str_get(str),&statcache);
  1159. #endif
  1160.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1161.     warn(warn_nl, "lstat");
  1162.     return laststatval;
  1163. }
  1164.  
  1165. STR *
  1166. do_fttext(arg,str)
  1167. register ARG *arg;
  1168. STR *str;
  1169. {
  1170.     int i;
  1171.     int len;
  1172.     int odd = 0;
  1173.     STDCHAR tbuf[512];
  1174.     register STDCHAR *s;
  1175.     register STIO *stio;
  1176.  
  1177.     if (arg[1].arg_type & A_DONT) {
  1178.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1179.         if (statstab)
  1180.         stio = stab_io(statstab);
  1181.         else {
  1182.         str = statname;
  1183.         goto really_filename;
  1184.         }
  1185.     }
  1186.     else {
  1187.         statstab = arg[1].arg_ptr.arg_stab;
  1188.         str_set(statname,"");
  1189.         stio = stab_io(statstab);
  1190.     }
  1191.     if (stio && stio->ifp) {
  1192. #if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
  1193.         fstat(fileno(stio->ifp),&statcache);
  1194.         if (S_ISDIR(statcache.st_mode))    /* handle NFS glitch */
  1195.         return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
  1196.         if (stio->ifp->_cnt <= 0) {
  1197.         i = getc(stio->ifp);
  1198.         if (i != EOF)
  1199.             (void)ungetc(i,stio->ifp);
  1200.         }
  1201.         if (stio->ifp->_cnt <= 0)    /* null file is anything */
  1202.         return &str_yes;
  1203.         len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
  1204.         s = stio->ifp->_base;
  1205. #else
  1206.         fatal("-T and -B not implemented on filehandles");
  1207. #endif
  1208.     }
  1209.     else {
  1210.         if (dowarn)
  1211.         warn("Test on unopened file <%s>",
  1212.           stab_ename(arg[1].arg_ptr.arg_stab));
  1213.         errno = EBADF;
  1214.         return &str_undef;
  1215.     }
  1216.     }
  1217.     else {
  1218.     statstab = Nullstab;
  1219.     str_set(statname,str_get(str));
  1220.       really_filename:
  1221.     i = open(str_get(str),0);
  1222.     if (i < 0) {
  1223.         if (dowarn && index(str_get(str), '\n'))
  1224.         warn(warn_nl, "open");
  1225.         return &str_undef;
  1226.     }
  1227.     fstat(i,&statcache);
  1228.     len = read(i,tbuf,512);
  1229.     (void)close(i);
  1230.     if (len <= 0) {
  1231.         if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
  1232.         return &str_no;        /* special case NFS directories */
  1233.         return &str_yes;        /* null file is anything */
  1234.     }
  1235.     s = tbuf;
  1236.     }
  1237.  
  1238.     /* now scan s to look for textiness */
  1239.  
  1240.     for (i = 0; i < len; i++,s++) {
  1241.     if (!*s) {            /* null never allowed in text */
  1242.         odd += len;
  1243.         break;
  1244.     }
  1245.     else if (*s & 128)
  1246.         odd++;
  1247.     else if (*s < 32 &&
  1248.       *s != '\n' && *s != '\r' && *s != '\b' &&
  1249.       *s != '\t' && *s != '\f' && *s != 27)
  1250.         odd++;
  1251.     }
  1252.  
  1253.     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1254.     return &str_no;
  1255.     else
  1256.     return &str_yes;
  1257. }
  1258.  
  1259. static char **Argv = Null(char **);
  1260. static char *Cmd = Nullch;
  1261.  
  1262. bool
  1263. do_aexec(really,arglast)
  1264. STR *really;
  1265. int *arglast;
  1266. {
  1267.     register STR **st = stack->ary_array;
  1268.     register int sp = arglast[1];
  1269.     register int items = arglast[2] - sp;
  1270.     register char **a;
  1271.     char *tmps;
  1272.  
  1273.     if (items) {
  1274.     New(401,Argv, items+1, char*);
  1275.     a = Argv;
  1276.     for (st += ++sp; items > 0; items--,st++) {
  1277.         if (*st)
  1278.         *a++ = str_get(*st);
  1279.         else
  1280.         *a++ = "";
  1281.     }
  1282.     *a = Nullch;
  1283. #ifdef TAINT
  1284.     if (*Argv[0] != '/')    /* will execvp use PATH? */
  1285.         taintenv();        /* testing IFS here is overkill, probably */
  1286. #endif
  1287. #ifdef DJGPP
  1288.     fatal("exec not supported - H.Doi");
  1289. #else
  1290.     if (really && *(tmps = str_get(really)))
  1291.         execvp(tmps,Argv);
  1292.     else
  1293.         execvp(Argv[0],Argv);
  1294. #endif /* DJGPP */
  1295.     }
  1296.     do_execfree();
  1297.     return FALSE;
  1298. }
  1299.  
  1300. void
  1301. do_execfree()
  1302. {
  1303.     if (Argv) {
  1304.     Safefree(Argv);
  1305.     Argv = Null(char **);
  1306.     }
  1307.     if (Cmd) {
  1308.     Safefree(Cmd);
  1309.     Cmd = Nullch;
  1310.     }
  1311. }
  1312.  
  1313. bool
  1314. do_exec(cmd)
  1315. char *cmd;
  1316. {
  1317.     register char **a;
  1318.     register char *s;
  1319.     char flags[10];
  1320.  
  1321.     /* save an extra exec if possible */
  1322.  
  1323. #ifdef CSH
  1324.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1325.     strcpy(flags,"-c");
  1326.     s = cmd+cshlen+3;
  1327.     if (*s == 'f') {
  1328.         s++;
  1329.         strcat(flags,"f");
  1330.     }
  1331.     if (*s == ' ')
  1332.         s++;
  1333.     if (*s++ == '\'') {
  1334.         char *ncmd = s;
  1335.  
  1336.         while (*s)
  1337.         s++;
  1338.         if (s[-1] == '\n')
  1339.         *--s = '\0';
  1340.         if (s[-1] == '\'') {
  1341.         *--s = '\0';
  1342. #ifdef DJGPP
  1343.         fatal("we don't have csh - H.Doi");
  1344. #else
  1345.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1346. #endif /* DJGPP */
  1347.         *s = '\'';
  1348.         return FALSE;
  1349.         }
  1350.     }
  1351.     }
  1352. #endif /* CSH */
  1353.  
  1354.     /* see if there are shell metacharacters in it */
  1355.  
  1356.     /*SUPPRESS 530*/
  1357.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1358.     if (*s == '=')
  1359.     goto doshell;
  1360.     for (s = cmd; *s; s++) {
  1361.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1362.         if (*s == '\n' && !s[1]) {
  1363.         *s = '\0';
  1364.         break;
  1365.         }
  1366.       doshell:
  1367. #ifdef DJGPP
  1368.         system(cmd);
  1369.         exit(0);
  1370. #else
  1371.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1372. #endif /* DJGPP */
  1373.         return FALSE;
  1374.     }
  1375.     }
  1376.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1377.     Cmd = nsavestr(cmd, s-cmd);
  1378.     a = Argv;
  1379.     for (s = Cmd; *s;) {
  1380.     while (*s && isSPACE(*s)) s++;
  1381.     if (*s)
  1382.         *(a++) = s;
  1383.     while (*s && !isSPACE(*s)) s++;
  1384.     if (*s)
  1385.         *s++ = '\0';
  1386.     }
  1387.     *a = Nullch;
  1388.     if (Argv[0]) {
  1389. #ifdef DJGPP
  1390.     system(cmd);
  1391.     exit(0);
  1392. #else
  1393.     execvp(Argv[0],Argv);
  1394. #endif /* DJGPP */
  1395.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1396.         do_execfree();
  1397.         goto doshell;
  1398.     }
  1399.     }
  1400.     do_execfree();
  1401.     return FALSE;
  1402. }
  1403.  
  1404. #ifdef HAS_SOCKET
  1405. int
  1406. do_socket(stab, arglast)
  1407. STAB *stab;
  1408. int *arglast;
  1409. {
  1410.     register STR **st = stack->ary_array;
  1411.     register int sp = arglast[1];
  1412.     register STIO *stio;
  1413.     int domain, type, protocol, fd;
  1414.  
  1415.     if (!stab) {
  1416.     errno = EBADF;
  1417.     return FALSE;
  1418.     }
  1419.  
  1420.     stio = stab_io(stab);
  1421.     if (!stio)
  1422.     stio = stab_io(stab) = stio_new();
  1423.     else if (stio->ifp)
  1424.     do_close(stab,FALSE);
  1425.  
  1426.     domain = (int)str_gnum(st[++sp]);
  1427.     type = (int)str_gnum(st[++sp]);
  1428.     protocol = (int)str_gnum(st[++sp]);
  1429. #ifdef TAINT
  1430.     taintproper("Insecure dependency in socket");
  1431. #endif
  1432.     fd = socket(domain,type,protocol);
  1433.     if (fd < 0)
  1434.     return FALSE;
  1435.     stio->ifp = fdopen(fd, "r");    /* stdio gets confused about sockets */
  1436.     stio->ofp = fdopen(fd, "w");
  1437.     stio->type = 's';
  1438.     if (!stio->ifp || !stio->ofp) {
  1439.     if (stio->ifp) fclose(stio->ifp);
  1440.     if (stio->ofp) fclose(stio->ofp);
  1441.     if (!stio->ifp && !stio->ofp) close(fd);
  1442.     return FALSE;
  1443.     }
  1444.  
  1445.     return TRUE;
  1446. }
  1447.  
  1448. int
  1449. do_bind(stab, arglast)
  1450. STAB *stab;
  1451. int *arglast;
  1452. {
  1453.     register STR **st = stack->ary_array;
  1454.     register int sp = arglast[1];
  1455.     register STIO *stio;
  1456.     char *addr;
  1457.  
  1458.     if (!stab)
  1459.     goto nuts;
  1460.  
  1461.     stio = stab_io(stab);
  1462.     if (!stio || !stio->ifp)
  1463.     goto nuts;
  1464.  
  1465.     addr = str_get(st[++sp]);
  1466. #ifdef TAINT
  1467.     taintproper("Insecure dependency in bind");
  1468. #endif
  1469.     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1470.  
  1471. nuts:
  1472.     if (dowarn)
  1473.     warn("bind() on closed fd");
  1474.     errno = EBADF;
  1475.     return FALSE;
  1476.  
  1477. }
  1478.  
  1479. int
  1480. do_connect(stab, arglast)
  1481. STAB *stab;
  1482. int *arglast;
  1483. {
  1484.     register STR **st = stack->ary_array;
  1485.     register int sp = arglast[1];
  1486.     register STIO *stio;
  1487.     char *addr;
  1488.  
  1489.     if (!stab)
  1490.     goto nuts;
  1491.  
  1492.     stio = stab_io(stab);
  1493.     if (!stio || !stio->ifp)
  1494.     goto nuts;
  1495.  
  1496.     addr = str_get(st[++sp]);
  1497. #ifdef TAINT
  1498.     taintproper("Insecure dependency in connect");
  1499. #endif
  1500.     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1501.  
  1502. nuts:
  1503.     if (dowarn)
  1504.     warn("connect() on closed fd");
  1505.     errno = EBADF;
  1506.     return FALSE;
  1507.  
  1508. }
  1509.  
  1510. int
  1511. do_listen(stab, arglast)
  1512. STAB *stab;
  1513. int *arglast;
  1514. {
  1515.     register STR **st = stack->ary_array;
  1516.     register int sp = arglast[1];
  1517.     register STIO *stio;
  1518.     int backlog;
  1519.  
  1520.     if (!stab)
  1521.     goto nuts;
  1522.  
  1523.     stio = stab_io(stab);
  1524.     if (!stio || !stio->ifp)
  1525.     goto nuts;
  1526.  
  1527.     backlog = (int)str_gnum(st[++sp]);
  1528.     return listen(fileno(stio->ifp), backlog) >= 0;
  1529.  
  1530. nuts:
  1531.     if (dowarn)
  1532.     warn("listen() on closed fd");
  1533.     errno = EBADF;
  1534.     return FALSE;
  1535. }
  1536.  
  1537. void
  1538. do_accept(str, nstab, gstab)
  1539. STR *str;
  1540. STAB *nstab;
  1541. STAB *gstab;
  1542. {
  1543.     register STIO *nstio;
  1544.     register STIO *gstio;
  1545.     int len = sizeof buf;
  1546.     int fd;
  1547.  
  1548.     if (!nstab)
  1549.     goto badexit;
  1550.     if (!gstab)
  1551.     goto nuts;
  1552.  
  1553.     gstio = stab_io(gstab);
  1554.     nstio = stab_io(nstab);
  1555.  
  1556.     if (!gstio || !gstio->ifp)
  1557.     goto nuts;
  1558.     if (!nstio)
  1559.     nstio = stab_io(nstab) = stio_new();
  1560.     else if (nstio->ifp)
  1561.     do_close(nstab,FALSE);
  1562.  
  1563.     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
  1564.     if (fd < 0)
  1565.     goto badexit;
  1566.     nstio->ifp = fdopen(fd, "r");
  1567.     nstio->ofp = fdopen(fd, "w");
  1568.     nstio->type = 's';
  1569.     if (!nstio->ifp || !nstio->ofp) {
  1570.     if (nstio->ifp) fclose(nstio->ifp);
  1571.     if (nstio->ofp) fclose(nstio->ofp);
  1572.     if (!nstio->ifp && !nstio->ofp) close(fd);
  1573.     goto badexit;
  1574.     }
  1575.  
  1576.     str_nset(str, buf, len);
  1577.     return;
  1578.  
  1579. nuts:
  1580.     if (dowarn)
  1581.     warn("accept() on closed fd");
  1582.     errno = EBADF;
  1583. badexit:
  1584.     str_sset(str,&str_undef);
  1585.     return;
  1586. }
  1587.  
  1588. int
  1589. do_shutdown(stab, arglast)
  1590. STAB *stab;
  1591. int *arglast;
  1592. {
  1593.     register STR **st = stack->ary_array;
  1594.     register int sp = arglast[1];
  1595.     register STIO *stio;
  1596.     int how;
  1597.  
  1598.     if (!stab)
  1599.     goto nuts;
  1600.  
  1601.     stio = stab_io(stab);
  1602.     if (!stio || !stio->ifp)
  1603.     goto nuts;
  1604.  
  1605.     how = (int)str_gnum(st[++sp]);
  1606.     return shutdown(fileno(stio->ifp), how) >= 0;
  1607.  
  1608. nuts:
  1609.     if (dowarn)
  1610.     warn("shutdown() on closed fd");
  1611.     errno = EBADF;
  1612.     return FALSE;
  1613.  
  1614. }
  1615.  
  1616. int
  1617. do_sopt(optype, stab, arglast)
  1618. int optype;
  1619. STAB *stab;
  1620. int *arglast;
  1621. {
  1622.     register STR **st = stack->ary_array;
  1623.     register int sp = arglast[1];
  1624.     register STIO *stio;
  1625.     int fd;
  1626.     unsigned int lvl;
  1627.     unsigned int optname;
  1628.  
  1629.     if (!stab)
  1630.     goto nuts;
  1631.  
  1632.     stio = stab_io(stab);
  1633.     if (!stio || !stio->ifp)
  1634.     goto nuts;
  1635.  
  1636.     fd = fileno(stio->ifp);
  1637.     lvl = (unsigned int)str_gnum(st[sp+1]);
  1638.     optname = (unsigned int)str_gnum(st[sp+2]);
  1639.     switch (optype) {
  1640.     case O_GSOCKOPT:
  1641.     st[sp] = str_2mortal(Str_new(22,257));
  1642.     st[sp]->str_cur = 256;
  1643.     st[sp]->str_pok = 1;
  1644.     if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
  1645.             (int*)&st[sp]->str_cur) < 0)
  1646.         goto nuts;
  1647.     break;
  1648.     case O_SSOCKOPT:
  1649.     st[sp] = st[sp+3];
  1650.     if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
  1651.         goto nuts;
  1652.     st[sp] = &str_yes;
  1653.     break;
  1654.     }
  1655.     
  1656.     return sp;
  1657.  
  1658. nuts:
  1659.     if (dowarn)
  1660.     warn("[gs]etsockopt() on closed fd");
  1661.     st[sp] = &str_undef;
  1662.     errno = EBADF;
  1663.     return sp;
  1664.  
  1665. }
  1666.  
  1667. int
  1668. do_getsockname(optype, stab, arglast)
  1669. int optype;
  1670. STAB *stab;
  1671. int *arglast;
  1672. {
  1673.     register STR **st = stack->ary_array;
  1674.     register int sp = arglast[1];
  1675.     register STIO *stio;
  1676.     int fd;
  1677.  
  1678.     if (!stab)
  1679.     goto nuts;
  1680.  
  1681.     stio = stab_io(stab);
  1682.     if (!stio || !stio->ifp)
  1683.     goto nuts;
  1684.  
  1685.     st[sp] = str_2mortal(Str_new(22,257));
  1686.     st[sp]->str_cur = 256;
  1687.     st[sp]->str_pok = 1;
  1688.     fd = fileno(stio->ifp);
  1689.     switch (optype) {
  1690.     case O_GETSOCKNAME:
  1691.     if (getsockname(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1692.         goto nuts2;
  1693.     break;
  1694.     case O_GETPEERNAME:
  1695.     if (getpeername(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1696.         goto nuts2;
  1697.     break;
  1698.     }
  1699.     
  1700.     return sp;
  1701.  
  1702. nuts:
  1703.     if (dowarn)
  1704.     warn("get{sock,peer}name() on closed fd");
  1705.     errno = EBADF;
  1706. nuts2:
  1707.     st[sp] = &str_undef;
  1708.     return sp;
  1709.  
  1710. }
  1711.  
  1712. int
  1713. do_ghent(which,gimme,arglast)
  1714. int which;
  1715. int gimme;
  1716. int *arglast;
  1717. {
  1718.     register ARRAY *ary = stack;
  1719.     register int sp = arglast[0];
  1720.     register char **elem;
  1721.     register STR *str;
  1722.     struct hostent *gethostbyname();
  1723.     struct hostent *gethostbyaddr();
  1724. #ifdef HAS_GETHOSTENT
  1725.     struct hostent *gethostent();
  1726. #endif
  1727.     struct hostent *hent;
  1728.     unsigned long len;
  1729.  
  1730.     if (which == O_GHBYNAME) {
  1731.     char *name = str_get(ary->ary_array[sp+1]);
  1732.  
  1733.     hent = gethostbyname(name);
  1734.     }
  1735.     else if (which == O_GHBYADDR) {
  1736.     STR *addrstr = ary->ary_array[sp+1];
  1737.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1738.     char *addr = str_get(addrstr);
  1739.  
  1740.     hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
  1741.     }
  1742.     else
  1743. #ifdef HAS_GETHOSTENT
  1744.     hent = gethostent();
  1745. #else
  1746.     fatal("gethostent not implemented");
  1747. #endif
  1748.  
  1749. #ifdef HOST_NOT_FOUND
  1750.     if (!hent)
  1751.     statusvalue = (unsigned short)h_errno & 0xffff;
  1752. #endif
  1753.  
  1754.     if (gimme != G_ARRAY) {
  1755.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1756.     if (hent) {
  1757.         if (which == O_GHBYNAME) {
  1758. #ifdef h_addr
  1759.         str_nset(str, *hent->h_addr, hent->h_length);
  1760. #else
  1761.         str_nset(str, hent->h_addr, hent->h_length);
  1762. #endif
  1763.         }
  1764.         else
  1765.         str_set(str, hent->h_name);
  1766.     }
  1767.     return sp;
  1768.     }
  1769.  
  1770.     if (hent) {
  1771. #ifndef lint
  1772.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1773.     str_set(str, hent->h_name);
  1774.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1775.     for (elem = hent->h_aliases; *elem; elem++) {
  1776.         str_cat(str, *elem);
  1777.         if (elem[1])
  1778.         str_ncat(str," ",1);
  1779.     }
  1780.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1781.     str_numset(str, (double)hent->h_addrtype);
  1782.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1783.     len = hent->h_length;
  1784.     str_numset(str, (double)len);
  1785. #ifdef h_addr
  1786.     for (elem = hent->h_addr_list; *elem; elem++) {
  1787.         (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1788.         str_nset(str, *elem, len);
  1789.     }
  1790. #else
  1791.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1792.     str_nset(str, hent->h_addr, len);
  1793. #endif /* h_addr */
  1794. #else /* lint */
  1795.     elem = Nullch;
  1796.     elem = elem;
  1797.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1798. #endif /* lint */
  1799.     }
  1800.  
  1801.     return sp;
  1802. }
  1803.  
  1804. int
  1805. do_gnent(which,gimme,arglast)
  1806. int which;
  1807. int gimme;
  1808. int *arglast;
  1809. {
  1810.     register ARRAY *ary = stack;
  1811.     register int sp = arglast[0];
  1812.     register char **elem;
  1813.     register STR *str;
  1814.     struct netent *getnetbyname();
  1815.     struct netent *getnetbyaddr();
  1816.     struct netent *getnetent();
  1817.     struct netent *nent;
  1818.  
  1819.     if (which == O_GNBYNAME) {
  1820.     char *name = str_get(ary->ary_array[sp+1]);
  1821.  
  1822.     nent = getnetbyname(name);
  1823.     }
  1824.     else if (which == O_GNBYADDR) {
  1825.     unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
  1826.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1827.  
  1828.     nent = getnetbyaddr((long)addr,addrtype);
  1829.     }
  1830.     else
  1831.     nent = getnetent();
  1832.  
  1833.     if (gimme != G_ARRAY) {
  1834.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1835.     if (nent) {
  1836.         if (which == O_GNBYNAME)
  1837.         str_numset(str, (double)nent->n_net);
  1838.         else
  1839.         str_set(str, nent->n_name);
  1840.     }
  1841.     return sp;
  1842.     }
  1843.  
  1844.     if (nent) {
  1845. #ifndef lint
  1846.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1847.     str_set(str, nent->n_name);
  1848.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1849.     for (elem = nent->n_aliases; *elem; elem++) {
  1850.         str_cat(str, *elem);
  1851.         if (elem[1])
  1852.         str_ncat(str," ",1);
  1853.     }
  1854.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1855.     str_numset(str, (double)nent->n_addrtype);
  1856.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1857.     str_numset(str, (double)nent->n_net);
  1858. #else /* lint */
  1859.     elem = Nullch;
  1860.     elem = elem;
  1861.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1862. #endif /* lint */
  1863.     }
  1864.  
  1865.     return sp;
  1866. }
  1867.  
  1868. int
  1869. do_gpent(which,gimme,arglast)
  1870. int which;
  1871. int gimme;
  1872. int *arglast;
  1873. {
  1874.     register ARRAY *ary = stack;
  1875.     register int sp = arglast[0];
  1876.     register char **elem;
  1877.     register STR *str;
  1878.     struct protoent *getprotobyname();
  1879.     struct protoent *getprotobynumber();
  1880.     struct protoent *getprotoent();
  1881.     struct protoent *pent;
  1882.  
  1883.     if (which == O_GPBYNAME) {
  1884.     char *name = str_get(ary->ary_array[sp+1]);
  1885.  
  1886.     pent = getprotobyname(name);
  1887.     }
  1888.     else if (which == O_GPBYNUMBER) {
  1889.     int proto = (int)str_gnum(ary->ary_array[sp+1]);
  1890.  
  1891.     pent = getprotobynumber(proto);
  1892.     }
  1893.     else
  1894.     pent = getprotoent();
  1895.  
  1896.     if (gimme != G_ARRAY) {
  1897.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1898.     if (pent) {
  1899.         if (which == O_GPBYNAME)
  1900.         str_numset(str, (double)pent->p_proto);
  1901.         else
  1902.         str_set(str, pent->p_name);
  1903.     }
  1904.     return sp;
  1905.     }
  1906.  
  1907.     if (pent) {
  1908. #ifndef lint
  1909.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1910.     str_set(str, pent->p_name);
  1911.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1912.     for (elem = pent->p_aliases; *elem; elem++) {
  1913.         str_cat(str, *elem);
  1914.         if (elem[1])
  1915.         str_ncat(str," ",1);
  1916.     }
  1917.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1918.     str_numset(str, (double)pent->p_proto);
  1919. #else /* lint */
  1920.     elem = Nullch;
  1921.     elem = elem;
  1922.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1923. #endif /* lint */
  1924.     }
  1925.  
  1926.     return sp;
  1927. }
  1928.  
  1929. int
  1930. do_gsent(which,gimme,arglast)
  1931. int which;
  1932. int gimme;
  1933. int *arglast;
  1934. {
  1935.     register ARRAY *ary = stack;
  1936.     register int sp = arglast[0];
  1937.     register char **elem;
  1938.     register STR *str;
  1939.     struct servent *getservbyname();
  1940.     struct servent *getservbynumber();
  1941.     struct servent *getservent();
  1942.     struct servent *sent;
  1943.  
  1944.     if (which == O_GSBYNAME) {
  1945.     char *name = str_get(ary->ary_array[sp+1]);
  1946.     char *proto = str_get(ary->ary_array[sp+2]);
  1947.  
  1948.     if (proto && !*proto)
  1949.         proto = Nullch;
  1950.  
  1951.     sent = getservbyname(name,proto);
  1952.     }
  1953.     else if (which == O_GSBYPORT) {
  1954.     int port = (int)str_gnum(ary->ary_array[sp+1]);
  1955.     char *proto = str_get(ary->ary_array[sp+2]);
  1956.  
  1957.     sent = getservbyport(port,proto);
  1958.     }
  1959.     else
  1960.     sent = getservent();
  1961.  
  1962.     if (gimme != G_ARRAY) {
  1963.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1964.     if (sent) {
  1965.         if (which == O_GSBYNAME) {
  1966. #ifdef HAS_NTOHS
  1967.         str_numset(str, (double)ntohs(sent->s_port));
  1968. #else
  1969.         str_numset(str, (double)(sent->s_port));
  1970. #endif
  1971.         }
  1972.         else
  1973.         str_set(str, sent->s_name);
  1974.     }
  1975.     return sp;
  1976.     }
  1977.  
  1978.     if (sent) {
  1979. #ifndef lint
  1980.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1981.     str_set(str, sent->s_name);
  1982.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1983.     for (elem = sent->s_aliases; *elem; elem++) {
  1984.         str_cat(str, *elem);
  1985.         if (elem[1])
  1986.         str_ncat(str," ",1);
  1987.     }
  1988.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1989. #ifdef HAS_NTOHS
  1990.     str_numset(str, (double)ntohs(sent->s_port));
  1991. #else
  1992.     str_numset(str, (double)(sent->s_port));
  1993. #endif
  1994.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1995.     str_set(str, sent->s_proto);
  1996. #else /* lint */
  1997.     elem = Nullch;
  1998.     elem = elem;
  1999.     (void)astore(ary, ++sp, str_mortal(&str_no));
  2000. #endif /* lint */
  2001.     }
  2002.  
  2003.     return sp;
  2004. }
  2005.  
  2006. #endif /* HAS_SOCKET */
  2007.  
  2008. #ifdef HAS_SELECT
  2009. int
  2010. do_select(gimme,arglast)
  2011. int gimme;
  2012. int *arglast;
  2013. {
  2014.     register STR **st = stack->ary_array;
  2015.     register int sp = arglast[0];
  2016.     register int i;
  2017.     register int j;
  2018.     register char *s;
  2019.     register STR *str;
  2020.     double value;
  2021.     int maxlen = 0;
  2022.     int nfound;
  2023.     struct timeval timebuf;
  2024.     struct timeval *tbuf = &timebuf;
  2025.     int growsize;
  2026. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2027.     int masksize;
  2028.     int offset;
  2029.     char *fd_sets[4];
  2030.     int k;
  2031.  
  2032. #if BYTEORDER & 0xf0000
  2033. #define ORDERBYTE (0x88888888 - BYTEORDER)
  2034. #else
  2035. #define ORDERBYTE (0x4444 - BYTEORDER)
  2036. #endif
  2037.  
  2038. #endif
  2039.  
  2040.     for (i = 1; i <= 3; i++) {
  2041.     j = st[sp+i]->str_cur;
  2042.     if (maxlen < j)
  2043.         maxlen = j;
  2044.     }
  2045.  
  2046. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2047.     growsize = maxlen;        /* little endians can use vecs directly */
  2048. #else
  2049. #ifdef NFDBITS
  2050.  
  2051. #ifndef NBBY
  2052. #define NBBY 8
  2053. #endif
  2054.  
  2055.     masksize = NFDBITS / NBBY;
  2056. #else
  2057.     masksize = sizeof(long);    /* documented int, everyone seems to use long */
  2058. #endif
  2059.     growsize = maxlen + (masksize - (maxlen % masksize));
  2060.     Zero(&fd_sets[0], 4, char*);
  2061. #endif
  2062.  
  2063.     for (i = 1; i <= 3; i++) {
  2064.     str = st[sp+i];
  2065.     j = str->str_len;
  2066.     if (j < growsize) {
  2067.         if (str->str_pok) {
  2068.         Str_Grow(str,growsize);
  2069.         s = str_get(str) + j;
  2070.         while (++j <= growsize) {
  2071.             *s++ = '\0';
  2072.         }
  2073.         }
  2074.         else if (str->str_ptr) {
  2075.         Safefree(str->str_ptr);
  2076.         str->str_ptr = Nullch;
  2077.         }
  2078.     }
  2079. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2080.     s = str->str_ptr;
  2081.     if (s) {
  2082.         New(403, fd_sets[i], growsize, char);
  2083.         for (offset = 0; offset < growsize; offset += masksize) {
  2084.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2085.             fd_sets[i][j+offset] = s[(k % masksize) + offset];
  2086.         }
  2087.     }
  2088. #endif
  2089.     }
  2090.     str = st[sp+4];
  2091.     if (str->str_nok || str->str_pok) {
  2092.     value = str_gnum(str);
  2093.     if (value < 0.0)
  2094.         value = 0.0;
  2095.     timebuf.tv_sec = (long)value;
  2096.     value -= (double)timebuf.tv_sec;
  2097.     timebuf.tv_usec = (long)(value * 1000000.0);
  2098.     }
  2099.     else
  2100.     tbuf = Null(struct timeval*);
  2101.  
  2102. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2103.     nfound = select(
  2104.     maxlen * 8,
  2105.     st[sp+1]->str_ptr,
  2106.     st[sp+2]->str_ptr,
  2107.     st[sp+3]->str_ptr,
  2108.     tbuf);
  2109. #else
  2110.     nfound = select(
  2111.     maxlen * 8,
  2112.     fd_sets[1],
  2113.     fd_sets[2],
  2114.     fd_sets[3],
  2115.     tbuf);
  2116.     for (i = 1; i <= 3; i++) {
  2117.     if (fd_sets[i]) {
  2118.         str = st[sp+i];
  2119.         s = str->str_ptr;
  2120.         for (offset = 0; offset < growsize; offset += masksize) {
  2121.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2122.             s[(k % masksize) + offset] = fd_sets[i][j+offset];
  2123.         }
  2124.         Safefree(fd_sets[i]);
  2125.     }
  2126.     }
  2127. #endif
  2128.  
  2129.     st[++sp] = str_mortal(&str_no);
  2130.     str_numset(st[sp], (double)nfound);
  2131.     if (gimme == G_ARRAY && tbuf) {
  2132.     value = (double)(timebuf.tv_sec) +
  2133.         (double)(timebuf.tv_usec) / 1000000.0;
  2134.     st[++sp] = str_mortal(&str_no);
  2135.     str_numset(st[sp], value);
  2136.     }
  2137.     return sp;
  2138. }
  2139. #endif /* SELECT */
  2140.  
  2141. #ifdef HAS_SOCKET
  2142. int
  2143. do_spair(stab1, stab2, arglast)
  2144. STAB *stab1;
  2145. STAB *stab2;
  2146. int *arglast;
  2147. {
  2148.     register STR **st = stack->ary_array;
  2149.     register int sp = arglast[2];
  2150.     register STIO *stio1;
  2151.     register STIO *stio2;
  2152.     int domain, type, protocol, fd[2];
  2153.  
  2154.     if (!stab1 || !stab2)
  2155.     return FALSE;
  2156.  
  2157.     stio1 = stab_io(stab1);
  2158.     stio2 = stab_io(stab2);
  2159.     if (!stio1)
  2160.     stio1 = stab_io(stab1) = stio_new();
  2161.     else if (stio1->ifp)
  2162.     do_close(stab1,FALSE);
  2163.     if (!stio2)
  2164.     stio2 = stab_io(stab2) = stio_new();
  2165.     else if (stio2->ifp)
  2166.     do_close(stab2,FALSE);
  2167.  
  2168.     domain = (int)str_gnum(st[++sp]);
  2169.     type = (int)str_gnum(st[++sp]);
  2170.     protocol = (int)str_gnum(st[++sp]);
  2171. #ifdef TAINT
  2172.     taintproper("Insecure dependency in socketpair");
  2173. #endif
  2174. #ifdef HAS_SOCKETPAIR
  2175.     if (socketpair(domain,type,protocol,fd) < 0)
  2176.     return FALSE;
  2177. #else
  2178.     fatal("Socketpair unimplemented");
  2179. #endif
  2180.     stio1->ifp = fdopen(fd[0], "r");
  2181.     stio1->ofp = fdopen(fd[0], "w");
  2182.     stio1->type = 's';
  2183.     stio2->ifp = fdopen(fd[1], "r");
  2184.     stio2->ofp = fdopen(fd[1], "w");
  2185.     stio2->type = 's';
  2186.     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
  2187.     if (stio1->ifp) fclose(stio1->ifp);
  2188.     if (stio1->ofp) fclose(stio1->ofp);
  2189.     if (!stio1->ifp && !stio1->ofp) close(fd[0]);
  2190.     if (stio2->ifp) fclose(stio2->ifp);
  2191.     if (stio2->ofp) fclose(stio2->ofp);
  2192.     if (!stio2->ifp && !stio2->ofp) close(fd[1]);
  2193.     return FALSE;
  2194.     }
  2195.  
  2196.     return TRUE;
  2197. }
  2198.  
  2199. #endif /* HAS_SOCKET */
  2200.  
  2201. int
  2202. do_gpwent(which,gimme,arglast)
  2203. int which;
  2204. int gimme;
  2205. int *arglast;
  2206. {
  2207. #ifdef I_PWD
  2208.     register ARRAY *ary = stack;
  2209.     register int sp = arglast[0];
  2210.     register STR *str;
  2211.     struct passwd *getpwnam();
  2212.     struct passwd *getpwuid();
  2213.     struct passwd *getpwent();
  2214.     struct passwd *pwent;
  2215.  
  2216.     if (which == O_GPWNAM) {
  2217.     char *name = str_get(ary->ary_array[sp+1]);
  2218.  
  2219.     pwent = getpwnam(name);
  2220.     }
  2221.     else if (which == O_GPWUID) {
  2222.     int uid = (int)str_gnum(ary->ary_array[sp+1]);
  2223.  
  2224.     pwent = getpwuid(uid);
  2225.     }
  2226.     else
  2227.     pwent = getpwent();
  2228.  
  2229.     if (gimme != G_ARRAY) {
  2230.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2231.     if (pwent) {
  2232.         if (which == O_GPWNAM)
  2233.         str_numset(str, (double)pwent->pw_uid);
  2234.         else
  2235.         str_set(str, pwent->pw_name);
  2236.     }
  2237.     return sp;
  2238.     }
  2239.  
  2240.     if (pwent) {
  2241.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2242.     str_set(str, pwent->pw_name);
  2243.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2244.     str_set(str, pwent->pw_passwd);
  2245.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2246.     str_numset(str, (double)pwent->pw_uid);
  2247.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2248.     str_numset(str, (double)pwent->pw_gid);
  2249.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2250. #ifdef PWCHANGE
  2251.     str_numset(str, (double)pwent->pw_change);
  2252. #else
  2253. #ifdef PWQUOTA
  2254.     str_numset(str, (double)pwent->pw_quota);
  2255. #else
  2256. #ifdef PWAGE
  2257.     str_set(str, pwent->pw_age);
  2258. #endif
  2259. #endif
  2260. #endif
  2261.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2262. #ifdef PWCLASS
  2263.     str_set(str,pwent->pw_class);
  2264. #else
  2265. #ifdef PWCOMMENT
  2266.     str_set(str, pwent->pw_comment);
  2267. #endif
  2268. #endif
  2269.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2270.     str_set(str, pwent->pw_gecos);
  2271.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2272.     str_set(str, pwent->pw_dir);
  2273.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2274.     str_set(str, pwent->pw_shell);
  2275. #ifdef PWEXPIRE
  2276.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2277.     str_numset(str, (double)pwent->pw_expire);
  2278. #endif
  2279.     }
  2280.  
  2281.     return sp;
  2282. #else
  2283.     fatal("password routines not implemented");
  2284. #endif
  2285. }
  2286.  
  2287. int
  2288. do_ggrent(which,gimme,arglast)
  2289. int which;
  2290. int gimme;
  2291. int *arglast;
  2292. {
  2293. #ifdef I_GRP
  2294.     register ARRAY *ary = stack;
  2295.     register int sp = arglast[0];
  2296.     register char **elem;
  2297.     register STR *str;
  2298.     struct group *getgrnam();
  2299.     struct group *getgrgid();
  2300.     struct group *getgrent();
  2301.     struct group *grent;
  2302.  
  2303.     if (which == O_GGRNAM) {
  2304.     char *name = str_get(ary->ary_array[sp+1]);
  2305.  
  2306.     grent = getgrnam(name);
  2307.     }
  2308.     else if (which == O_GGRGID) {
  2309.     int gid = (int)str_gnum(ary->ary_array[sp+1]);
  2310.  
  2311.     grent = getgrgid(gid);
  2312.     }
  2313.     else
  2314.     grent = getgrent();
  2315.  
  2316.     if (gimme != G_ARRAY) {
  2317.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2318.     if (grent) {
  2319.         if (which == O_GGRNAM)
  2320.         str_numset(str, (double)grent->gr_gid);
  2321.         else
  2322.         str_set(str, grent->gr_name);
  2323.     }
  2324.     return sp;
  2325.     }
  2326.  
  2327.     if (grent) {
  2328.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2329.     str_set(str, grent->gr_name);
  2330.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2331.     str_set(str, grent->gr_passwd);
  2332.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2333.     str_numset(str, (double)grent->gr_gid);
  2334.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2335.     for (elem = grent->gr_mem; *elem; elem++) {
  2336.         str_cat(str, *elem);
  2337.         if (elem[1])
  2338.         str_ncat(str," ",1);
  2339.     }
  2340.     }
  2341.  
  2342.     return sp;
  2343. #else
  2344.     fatal("group routines not implemented");
  2345. #endif
  2346. }
  2347.  
  2348. int
  2349. do_dirop(optype,stab,gimme,arglast)
  2350. int optype;
  2351. STAB *stab;
  2352. int gimme;
  2353. int *arglast;
  2354. {
  2355. #if defined(DIRENT) && defined(HAS_READDIR)
  2356.     register ARRAY *ary = stack;
  2357.     register STR **st = ary->ary_array;
  2358.     register int sp = arglast[1];
  2359.     register STIO *stio;
  2360.     long along;
  2361. #ifndef apollo
  2362.     struct DIRENT *readdir();
  2363. #endif
  2364.     register struct DIRENT *dp;
  2365.  
  2366.     if (!stab)
  2367.     goto nope;
  2368.     if (!(stio = stab_io(stab)))
  2369.     stio = stab_io(stab) = stio_new();
  2370.     if (!stio->dirp && optype != O_OPEN_DIR)
  2371.     goto nope;
  2372.     st[sp] = &str_yes;
  2373.     switch (optype) {
  2374.     case O_OPEN_DIR:
  2375.     if (stio->dirp)
  2376.         closedir(stio->dirp);
  2377.     if (!(stio->dirp = opendir(str_get(st[sp+1]))))
  2378.         goto nope;
  2379.     break;
  2380.     case O_READDIR:
  2381.     if (gimme == G_ARRAY) {
  2382.         --sp;
  2383.         /*SUPPRESS 560*/
  2384.         while (dp = readdir(stio->dirp)) {
  2385. #ifdef DIRNAMLEN
  2386.         (void)astore(ary,++sp,
  2387.           str_2mortal(str_make(dp->d_name,dp->d_namlen)));
  2388. #else
  2389.         (void)astore(ary,++sp,
  2390.           str_2mortal(str_make(dp->d_name,0)));
  2391. #endif
  2392.         }
  2393.     }
  2394.     else {
  2395.         if (!(dp = readdir(stio->dirp)))
  2396.         goto nope;
  2397.         st[sp] = str_mortal(&str_undef);
  2398. #ifdef DIRNAMLEN
  2399.         str_nset(st[sp], dp->d_name, dp->d_namlen);
  2400. #else
  2401.         str_set(st[sp], dp->d_name);
  2402. #endif
  2403.     }
  2404.     break;
  2405. #if defined(HAS_TELLDIR) || defined(telldir)
  2406.     case O_TELLDIR: {
  2407. #ifndef telldir
  2408.         long telldir();
  2409. #endif
  2410.         st[sp] = str_mortal(&str_undef);
  2411.         str_numset(st[sp], (double)telldir(stio->dirp));
  2412.         break;
  2413.     }
  2414. #endif
  2415. #if defined(HAS_SEEKDIR) || defined(seekdir)
  2416.     case O_SEEKDIR:
  2417.     st[sp] = str_mortal(&str_undef);
  2418.     along = (long)str_gnum(st[sp+1]);
  2419.     (void)seekdir(stio->dirp,along);
  2420.     break;
  2421. #endif
  2422. #if defined(HAS_REWINDDIR) || defined(rewinddir)
  2423.     case O_REWINDDIR:
  2424.     st[sp] = str_mortal(&str_undef);
  2425.     (void)rewinddir(stio->dirp);
  2426.     break;
  2427. #endif
  2428.     case O_CLOSEDIR:
  2429.     st[sp] = str_mortal(&str_undef);
  2430.     (void)closedir(stio->dirp);
  2431.     stio->dirp = 0;
  2432.     break;
  2433.     default:
  2434.     goto phooey;
  2435.     }
  2436.     return sp;
  2437.  
  2438. nope:
  2439.     st[sp] = &str_undef;
  2440.     if (!errno)
  2441.     errno = EBADF;
  2442.     return sp;
  2443.  
  2444. #endif
  2445. phooey:
  2446.     fatal("Unimplemented directory operation");
  2447. }
  2448.  
  2449. int
  2450. apply(type,arglast)
  2451. int type;
  2452. int *arglast;
  2453. {
  2454.     register STR **st = stack->ary_array;
  2455.     register int sp = arglast[1];
  2456.     register int items = arglast[2] - sp;
  2457.     register int val;
  2458.     register int val2;
  2459.     register int tot = 0;
  2460.     char *s;
  2461.  
  2462. #ifdef TAINT
  2463.     for (st += ++sp; items--; st++)
  2464.     tainted |= (*st)->str_tainted;
  2465.     st = stack->ary_array;
  2466.     sp = arglast[1];
  2467.     items = arglast[2] - sp;
  2468. #endif
  2469.     switch (type) {
  2470.     case O_CHMOD:
  2471. #ifdef TAINT
  2472.     taintproper("Insecure dependency in chmod");
  2473. #endif
  2474.     if (--items > 0) {
  2475.         tot = items;
  2476.         val = (int)str_gnum(st[++sp]);
  2477.         while (items--) {
  2478.         if (chmod(str_get(st[++sp]),val))
  2479.             tot--;
  2480.         }
  2481.     }
  2482.     break;
  2483. #ifdef HAS_CHOWN
  2484.     case O_CHOWN:
  2485. #ifdef TAINT
  2486.     taintproper("Insecure dependency in chown");
  2487. #endif
  2488.     if (items > 2) {
  2489.         items -= 2;
  2490.         tot = items;
  2491.         val = (int)str_gnum(st[++sp]);
  2492.         val2 = (int)str_gnum(st[++sp]);
  2493.         while (items--) {
  2494.         if (chown(str_get(st[++sp]),val,val2))
  2495.             tot--;
  2496.         }
  2497.     }
  2498.     break;
  2499. #endif
  2500. #ifdef HAS_KILL
  2501.     case O_KILL:
  2502. #ifdef TAINT
  2503.     taintproper("Insecure dependency in kill");
  2504. #endif
  2505.     if (--items > 0) {
  2506.         tot = items;
  2507.         s = str_get(st[++sp]);
  2508.         if (isUPPER(*s)) {
  2509.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  2510.             s += 3;
  2511.         if (!(val = whichsig(s)))
  2512.             fatal("Unrecognized signal name \"%s\"",s);
  2513.         }
  2514.         else
  2515.         val = (int)str_gnum(st[sp]);
  2516.         if (val < 0) {
  2517.         val = -val;
  2518.         while (items--) {
  2519.             int proc = (int)str_gnum(st[++sp]);
  2520. #ifdef HAS_KILLPG
  2521.             if (killpg(proc,val))    /* BSD */
  2522. #else
  2523.             if (kill(-proc,val))    /* SYSV */
  2524. #endif
  2525.             tot--;
  2526.         }
  2527.         }
  2528.         else {
  2529.         while (items--) {
  2530.             if (kill((int)(str_gnum(st[++sp])),val))
  2531.             tot--;
  2532.         }
  2533.         }
  2534.     }
  2535.     break;
  2536. #endif
  2537.     case O_UNLINK:
  2538. #ifdef TAINT
  2539.     taintproper("Insecure dependency in unlink");
  2540. #endif
  2541.     tot = items;
  2542.     while (items--) {
  2543.         s = str_get(st[++sp]);
  2544.         if (euid || unsafe) {
  2545.         if (UNLINK(s))
  2546.             tot--;
  2547.         }
  2548.         else {    /* don't let root wipe out directories without -U */
  2549. #ifdef HAS_LSTAT
  2550.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2551. #else
  2552.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2553. #endif
  2554.             tot--;
  2555.         else {
  2556.             if (UNLINK(s))
  2557.             tot--;
  2558.         }
  2559.         }
  2560.     }
  2561.     break;
  2562.     case O_UTIME:
  2563. #ifdef TAINT
  2564.     taintproper("Insecure dependency in utime");
  2565. #endif
  2566.     if (items > 2) {
  2567. #ifdef I_UTIME
  2568.         struct utimbuf utbuf;
  2569. #else
  2570.         struct {
  2571.         long    actime;
  2572.         long    modtime;
  2573.         } utbuf;
  2574. #endif
  2575.  
  2576.         Zero(&utbuf, sizeof utbuf, char);
  2577.         utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
  2578.         utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
  2579.         items -= 2;
  2580. #ifndef lint
  2581.         tot = items;
  2582.         while (items--) {
  2583.         if (utime(str_get(st[++sp]),&utbuf))
  2584.             tot--;
  2585.         }
  2586. #endif
  2587.     }
  2588.     else
  2589.         items = 0;
  2590.     break;
  2591.     }
  2592.     return tot;
  2593. }
  2594.  
  2595. /* Do the permissions allow some operation?  Assumes statcache already set. */
  2596.  
  2597. int
  2598. cando(bit, effective, statbufp)
  2599. int bit;
  2600. int effective;
  2601. register struct stat *statbufp;
  2602. {
  2603. #ifdef DOSISH
  2604.     /* [Comments and code from Len Reed]
  2605.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  2606.      * to write-protected files.  The execute permission bit is set
  2607.      * by the Miscrosoft C library stat() function for the following:
  2608.      *        .exe files
  2609.      *        .com files
  2610.      *        .bat files
  2611.      *        directories
  2612.      * All files and directories are readable.
  2613.      * Directories and special files, e.g. "CON", cannot be
  2614.      * write-protected.
  2615.      * [Comment by Tom Dinger -- a directory can have the write-protect
  2616.      *        bit set in the file system, but DOS permits changes to
  2617.      *        the directory anyway.  In addition, all bets are off
  2618.      *        here for networked software, such as Novell and
  2619.      *        Sun's PC-NFS.]
  2620.      */
  2621.  
  2622.      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
  2623.       * too so it will actually look into the files for magic numbers
  2624.       */
  2625.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  2626.  
  2627. #else /* ! MSDOS */
  2628.     if ((effective ? euid : uid) == 0) {    /* root is special */
  2629.     if (bit == S_IXUSR) {
  2630.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  2631.         return TRUE;
  2632.     }
  2633.     else
  2634.         return TRUE;        /* root reads and writes anything */
  2635.     return FALSE;
  2636.     }
  2637.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  2638.     if (statbufp->st_mode & bit)
  2639.         return TRUE;    /* ok as "user" */
  2640.     }
  2641.     else if (ingroup((int)statbufp->st_gid,effective)) {
  2642.     if (statbufp->st_mode & bit >> 3)
  2643.         return TRUE;    /* ok as "group" */
  2644.     }
  2645.     else if (statbufp->st_mode & bit >> 6)
  2646.     return TRUE;    /* ok as "other" */
  2647.     return FALSE;
  2648. #endif /* ! MSDOS */
  2649. }
  2650.  
  2651. int
  2652. ingroup(testgid,effective)
  2653. int testgid;
  2654. int effective;
  2655. {
  2656.     if (testgid == (effective ? egid : gid))
  2657.     return TRUE;
  2658. #ifdef HAS_GETGROUPS
  2659. #ifndef NGROUPS
  2660. #define NGROUPS 32
  2661. #endif
  2662.     {
  2663.     GROUPSTYPE gary[NGROUPS];
  2664.     int anum;
  2665.  
  2666.     anum = getgroups(NGROUPS,gary);
  2667.     while (--anum >= 0)
  2668.         if (gary[anum] == testgid)
  2669.         return TRUE;
  2670.     }
  2671. #endif
  2672.     return FALSE;
  2673. }
  2674.  
  2675. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  2676.  
  2677. int
  2678. do_ipcget(optype, arglast)
  2679. int optype;
  2680. int *arglast;
  2681. {
  2682.     register STR **st = stack->ary_array;
  2683.     register int sp = arglast[0];
  2684.     key_t key;
  2685.     int n, flags;
  2686.  
  2687.     key = (key_t)str_gnum(st[++sp]);
  2688.     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
  2689.     flags = (int)str_gnum(st[++sp]);
  2690.     errno = 0;
  2691.     switch (optype)
  2692.     {
  2693. #ifdef HAS_MSG
  2694.     case O_MSGGET:
  2695.     return msgget(key, flags);
  2696. #endif
  2697. #ifdef HAS_SEM
  2698.     case O_SEMGET:
  2699.     return semget(key, n, flags);
  2700. #endif
  2701. #ifdef HAS_SHM
  2702.     case O_SHMGET:
  2703.     return shmget(key, n, flags);
  2704. #endif
  2705. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2706.     default:
  2707.     fatal("%s not implemented", opname[optype]);
  2708. #endif
  2709.     }
  2710.     return -1;            /* should never happen */
  2711. }
  2712.  
  2713. int
  2714. do_ipcctl(optype, arglast)
  2715. int optype;
  2716. int *arglast;
  2717. {
  2718.     register STR **st = stack->ary_array;
  2719.     register int sp = arglast[0];
  2720.     STR *astr;
  2721.     char *a;
  2722.     int id, n, cmd, infosize, getinfo, ret;
  2723.  
  2724.     id = (int)str_gnum(st[++sp]);
  2725.     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
  2726.     cmd = (int)str_gnum(st[++sp]);
  2727.     astr = st[++sp];
  2728.  
  2729.     infosize = 0;
  2730.     getinfo = (cmd == IPC_STAT);
  2731.  
  2732.     switch (optype)
  2733.     {
  2734. #ifdef HAS_MSG
  2735.     case O_MSGCTL:
  2736.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2737.         infosize = sizeof(struct msqid_ds);
  2738.     break;
  2739. #endif
  2740. #ifdef HAS_SHM
  2741.     case O_SHMCTL:
  2742.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2743.         infosize = sizeof(struct shmid_ds);
  2744.     break;
  2745. #endif
  2746. #ifdef HAS_SEM
  2747.     case O_SEMCTL:
  2748.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2749.         infosize = sizeof(struct semid_ds);
  2750.     else if (cmd == GETALL || cmd == SETALL)
  2751.     {
  2752.         struct semid_ds semds;
  2753.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  2754.         return -1;
  2755.         getinfo = (cmd == GETALL);
  2756.         infosize = semds.sem_nsems * sizeof(short);
  2757.         /* "short" is technically wrong but much more portable
  2758.            than guessing about u_?short(_t)? */
  2759.     }
  2760.     break;
  2761. #endif
  2762. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2763.     default:
  2764.     fatal("%s not implemented", opname[optype]);
  2765. #endif
  2766.     }
  2767.  
  2768.     if (infosize)
  2769.     {
  2770.     if (getinfo)
  2771.     {
  2772.         STR_GROW(astr, infosize+1);
  2773.         a = str_get(astr);
  2774.     }
  2775.     else
  2776.     {
  2777.         a = str_get(astr);
  2778.         if (astr->str_cur != infosize)
  2779.         {
  2780.         errno = EINVAL;
  2781.         return -1;
  2782.         }
  2783.     }
  2784.     }
  2785.     else
  2786.     {
  2787.     int i = (int)str_gnum(astr);
  2788.     a = (char *)i;        /* ouch */
  2789.     }
  2790.     errno = 0;
  2791.     switch (optype)
  2792.     {
  2793. #ifdef HAS_MSG
  2794.     case O_MSGCTL:
  2795.     ret = msgctl(id, cmd, (struct msqid_ds *)a);
  2796.     break;
  2797. #endif
  2798. #ifdef HAS_SEM
  2799.     case O_SEMCTL:
  2800.     ret = semctl(id, n, cmd, a);
  2801.     break;
  2802. #endif
  2803. #ifdef HAS_SHM
  2804.     case O_SHMCTL:
  2805.     ret = shmctl(id, cmd, (struct shmid_ds *)a);
  2806.     break;
  2807. #endif
  2808.     }
  2809.     if (getinfo && ret >= 0) {
  2810.     astr->str_cur = infosize;
  2811.     astr->str_ptr[infosize] = '\0';
  2812.     }
  2813.     return ret;
  2814. }
  2815.  
  2816. int
  2817. do_msgsnd(arglast)
  2818. int *arglast;
  2819. {
  2820. #ifdef HAS_MSG
  2821.     register STR **st = stack->ary_array;
  2822.     register int sp = arglast[0];
  2823.     STR *mstr;
  2824.     char *mbuf;
  2825.     int id, msize, flags;
  2826.  
  2827.     id = (int)str_gnum(st[++sp]);
  2828.     mstr = st[++sp];
  2829.     flags = (int)str_gnum(st[++sp]);
  2830.     mbuf = str_get(mstr);
  2831.     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
  2832.     errno = EINVAL;
  2833.     return -1;
  2834.     }
  2835.     errno = 0;
  2836.     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
  2837. #else
  2838.     fatal("msgsnd not implemented");
  2839. #endif
  2840. }
  2841.  
  2842. int
  2843. do_msgrcv(arglast)
  2844. int *arglast;
  2845. {
  2846. #ifdef HAS_MSG
  2847.     register STR **st = stack->ary_array;
  2848.     register int sp = arglast[0];
  2849.     STR *mstr;
  2850.     char *mbuf;
  2851.     long mtype;
  2852.     int id, msize, flags, ret;
  2853.  
  2854.     id = (int)str_gnum(st[++sp]);
  2855.     mstr = st[++sp];
  2856.     msize = (int)str_gnum(st[++sp]);
  2857.     mtype = (long)str_gnum(st[++sp]);
  2858.     flags = (int)str_gnum(st[++sp]);
  2859.     mbuf = str_get(mstr);
  2860.     if (mstr->str_cur < sizeof(long)+msize+1) {
  2861.     STR_GROW(mstr, sizeof(long)+msize+1);
  2862.     mbuf = str_get(mstr);
  2863.     }
  2864.     errno = 0;
  2865.     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
  2866.     if (ret >= 0) {
  2867.     mstr->str_cur = sizeof(long)+ret;
  2868.     mstr->str_ptr[sizeof(long)+ret] = '\0';
  2869.     }
  2870.     return ret;
  2871. #else
  2872.     fatal("msgrcv not implemented");
  2873. #endif
  2874. }
  2875.  
  2876. int
  2877. do_semop(arglast)
  2878. int *arglast;
  2879. {
  2880. #ifdef HAS_SEM
  2881.     register STR **st = stack->ary_array;
  2882.     register int sp = arglast[0];
  2883.     STR *opstr;
  2884.     char *opbuf;
  2885.     int id, opsize;
  2886.  
  2887.     id = (int)str_gnum(st[++sp]);
  2888.     opstr = st[++sp];
  2889.     opbuf = str_get(opstr);
  2890.     opsize = opstr->str_cur;
  2891.     if (opsize < sizeof(struct sembuf)
  2892.     || (opsize % sizeof(struct sembuf)) != 0) {
  2893.     errno = EINVAL;
  2894.     return -1;
  2895.     }
  2896.     errno = 0;
  2897.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  2898. #else
  2899.     fatal("semop not implemented");
  2900. #endif
  2901. }
  2902.  
  2903. int
  2904. do_shmio(optype, arglast)
  2905. int optype;
  2906. int *arglast;
  2907. {
  2908. #ifdef HAS_SHM
  2909.     register STR **st = stack->ary_array;
  2910.     register int sp = arglast[0];
  2911.     STR *mstr;
  2912.     char *mbuf, *shm;
  2913.     int id, mpos, msize;
  2914.     struct shmid_ds shmds;
  2915. #ifndef VOIDSHMAT
  2916.     extern char *shmat();
  2917. #endif
  2918.  
  2919.     id = (int)str_gnum(st[++sp]);
  2920.     mstr = st[++sp];
  2921.     mpos = (int)str_gnum(st[++sp]);
  2922.     msize = (int)str_gnum(st[++sp]);
  2923.     errno = 0;
  2924.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  2925.     return -1;
  2926.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  2927.     errno = EFAULT;        /* can't do as caller requested */
  2928.     return -1;
  2929.     }
  2930.     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
  2931.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  2932.     return -1;
  2933.     mbuf = str_get(mstr);
  2934.     if (optype == O_SHMREAD) {
  2935.     if (mstr->str_cur < msize) {
  2936.         STR_GROW(mstr, msize+1);
  2937.         mbuf = str_get(mstr);
  2938.     }
  2939.     Copy(shm + mpos, mbuf, msize, char);
  2940.     mstr->str_cur = msize;
  2941.     mstr->str_ptr[msize] = '\0';
  2942.     }
  2943.     else {
  2944.     int n;
  2945.  
  2946.     if ((n = mstr->str_cur) > msize)
  2947.         n = msize;
  2948.     Copy(mbuf, shm + mpos, n, char);
  2949.     if (n < msize)
  2950.         memzero(shm + mpos + n, msize - n);
  2951.     }
  2952.     return shmdt(shm);
  2953. #else
  2954.     fatal("shm I/O not implemented");
  2955. #endif
  2956. }
  2957.  
  2958. #endif /* SYSV IPC */
  2959.